﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emil.GMP;
using System.Security.Cryptography;
using NUnit.Framework;

namespace BYU_ECC
{
	/// <summary>
	/// Key generation algorithms utilizing ECDH, or Elliptic Curve Diffie-Hellman
	/// </summary>
    class KeyPairs
    {
        #region KeySet Members and Properties

		private static KeySet keySetA;
		private static KeySet keySetB;

		public static Point PublicKeyA {
			get {
				CheckGenerated();
				return keySetA.PublicKey;
			}
		}

		public static Point PublicKeyB {
			get {
				CheckGenerated();
				return keySetB.PublicKey;
			}
		}

		public static BigInt PrivateKeyA {
			get {
				CheckGenerated();
				return keySetA.PrivateKey;
			}
		}

		public static BigInt PrivateKeyB {
			get {
				CheckGenerated();
				return keySetB.PrivateKey;
			}
		}
		public static Point SecretKeyA {
			get {
				CheckGenerated();
				return keySetA.PrivateKey*keySetB.PublicKey;
			}
		}

		public static Point SecretKeyB {
			get {
				CheckGenerated();
				return keySetB.PrivateKey*keySetA.PublicKey;
			}
		}

        #endregion

        #region Singleton Instance Functions
        private static KeyPairs instance;
        public KeyPairs Instance()
        {
            CheckGenerated();
            return instance;
        }
		public static void GenerateKeyPairs()
        {
			instance = new KeyPairs();
        }
		private KeyPairs()
        {
			keySetA = new KeySet();
			keySetB = new KeySet();
		}

		#endregion

		private static void CheckGenerated()
        {
            if (instance == null)
				throw new KeyPairsNotGeneratedException();
        }
    }

	class KeySet {
		#region Key members

		private BigInt d;
		public BigInt PrivateKey {
			get { return d; }
		}

		private Point q;
		public Point PublicKey {
			get { return q; }
		}

		#endregion
		
		public KeySet() {
			// Choose d = random integer between [1, n-1] where n is order of curve
			d = ParameterGenerator.GenerateRandomBigInt(ParameterGenerator.N-1);

			// Q = dG where G is the base point of the curve
			q = d*ParameterGenerator.BasePoint;
		}

		public override string ToString() {
			return "[Private-" + d + ", Public-" + q + "]";
		}
	}

	class KeyPairsNotGeneratedException : Exception { }

    #region KeyPairs Tests
    [TestFixture]
	class KeyPairsTests {
		[SetUp]
		public void SetUp() {
			ParameterGenerator.GenerateTestParameters(KeySizeEnum.Size192);
		}

		[Test]
		public void TestKeyGeneration() {
			KeyPairs.GenerateKeyPairs();

		}
    }
    #endregion
}
